/**
 * 
 */
package ase.eleitweg.common;

import java.util.*;
import java.io.*;
import org.apache.log4j.*;

/**
 * @author Aigner
 * 
 */
public class Workflow implements Serializable, ComparableByValue<Workflow> {

	private int wnr; // Unique workflow number
	private String name; // Name of a workflow
	private Date dateins; // Date of insertion
	private String description; // Description of the workflow
	private Node startnode; //
	
	private transient Logger log = Logger.getLogger(Workflow.class);

	public Workflow(int wnr, String name, Date dateins, String description) {
		this.wnr = wnr;
		this.name = name;
		this.dateins = dateins;
		this.description = description;
	}

	public Workflow(int wnr, String name, Date dateins, String description,
			Node startnode) {
		super();
		this.wnr = wnr;
		this.name = name;
		this.dateins = dateins;
		this.description = description;
		this.startnode = startnode;
	}

	public Node getStartnode() {
		return startnode;
	}

	public void setStartnode(Node startnode) {
		this.startnode = startnode;
	}

	public Workflow(int wnr) {
		this.wnr = wnr;
	}

	/* Getter/Setter Methods */

	public int getWNr() {
		return wnr;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Date getDate() {
		return dateins;
	}

	public void setDate(Date dateins) {
		this.dateins = dateins;
	}

	public String getDesc() {
		return description;
	}

	public void setDesc(String description) {
		this.description = description;
	}

	public void setWNr(int id) {
		this.wnr = id;
	}

	public Set<Node> getNodes() {
		Set<Node> startSet = new HashSet<Node>();
		
		//If startnode is null return a set with no element
		if(startnode!=null) startSet.add(startnode);
		else return startSet;
		
		return getNodesRecoursive(startnode, startSet);
	}

	private Set<Node> getNodesRecoursive(Node start, Set<Node> nodes) {

		Conditions c = start.getConditions();
		for (Edge g : c.getEdges()) {
			Node to = g.getToNode();

			if (!nodes.contains(to)) {
				//log.debug("adding: " + to.getName());
				nodes.add(to);
				nodes.addAll(getNodesRecoursive(to, nodes));
				// return nodes;
			}
		}
		return nodes;
	}

	public Workflow clone() {
		Workflow clone = new Workflow(0);
		clone.setDate(this.getDate());
		clone.setDesc(this.getDesc());
		clone.setName(this.getName());
		List<Node> cloneNodes = new Vector<Node>();
		// fist we make shallow copy of all nodes (without theire outgoing
		// edges)
		for (Node n : this.getNodes()) {
			Node n2 = new Node(n.getId(), n.getGroup(), n.getName(), n
					.getDescription(), null, clone);
			Conditions c2 = new Conditions(n2, n.getConditions().getTitel());
			n2.setConditions(c2);
			cloneNodes.add(n2);
		}
		// now iterate through the old node and find theire new counterparts
		// based on ids
		for (Node n : this.getNodes()) {
			for (Node n2 : cloneNodes) {
				// if we have found the counterparts, we can start recreating
				// its edges.
				if (n.getId() == n2.getId()) {
					// iterate over all edges of old node
					for (Edge e : n.getConditions().getEdges()) {
						Node toNode = e.getToNode();
						// now find the counterpart of the new node in our
						// cloneNodes
						for (Node toNode2 : cloneNodes) {
							if (toNode.getId() == toNode2.getId()) {
								Edge clonedEdge = new Edge(e.getDescription(),
										n2, toNode2);
								n2.getConditions().addEdge(clonedEdge);
							}
						}
					}
				}
			}
		}
		//now set the startnode
		for(Node n : cloneNodes) {
			if(this.getStartnode().getId() == n.getId()) {
				clone.setStartnode(n);
				break;
			}
		}
		//and now remove all the IDs
		for(Node n : cloneNodes) {
			n.setId(0);
			for(Edge e : n.getConditions().getEdges()) {
				e.setId(0);
			}
		}
		return clone;

	}

	public void resetIDs() {

	}

	public boolean isSame(Workflow w) {
		if(this.getDate().equals(w.getDate()) && this.getDesc().equals(w.getDesc()) && this.getWNr()==w.getWNr()) {
			for (Node n : this.getNodes()) {
				boolean found = false;
				for (Node n2 : w.getNodes()) {
					if(n.isSame(n2)) {
						found = true;
					}
				}
				if(!found) {
					return false;
				}
			}
			return true;
		} else {
		return false;
		}
	}
	
	public boolean isSimilar(Workflow w) {
		if(this.getDate().equals(w.getDate()) && this.getDesc().equals(w.getDesc())) {
			for (Node n : this.getNodes()) {
				boolean found = false;
				for (Node n2 : w.getNodes()) {
					if(n.isSimilar(n2)) {
						found = true;
					}
				}
				if(!found) {
					return false;
				}
			}
			return true;
		} else {
		return false;
		}
	}

}
